ecrecover を使用してメッセージの署名を検証する
署名検証は、あるメッセージに対して署名を行ったアカウントの公開鍵を得ることで、実現します。
公開鍵から Ethereum のアドレスを得ることができるので、どのアカウントが署名を行ったかがわかります。
署名者のアドレスと ecrecover によって得られたアドレスを比較し、比較した結果が同一だった場合に署名検証に成功とします。 署名検証の手順
1. 検証するメッセージと署名を用意します。
2. メッセージから Keccak ハッシュを得ます
3. ecrecover を使用して、メッセージのハッシュ、v, r, s から署名者の公開鍵を得ます。
4. ecrecover により得られた公開鍵から Ethereum アドレスを計算し、実際の署名者のアドレスと比較します。
サンプルコード
code:example.js
const EthUtil = require('ethereumjs-util')
// 署名者のアドレス
const SIGNER_ADDRESS_STRING = '0x89c24a88bad4abe0a4f5b2eb5a86db1fb323832c'
// メッセージ
const MSG = "piyopiyo!"
// 署名されたメッセージ
const SIGNED_MSG = {
r : '0xdd7fa0d0b259468434cf14760c6607f36f2d7429feaaaedf6d86265c11098d20',
s : '0x14cf83d2204e50b12fcb2445a70c214509d0f4edf0e0ee6e8d18fed8fbb146c0',
v : 27
}
// メッセージ の Keccak ハッシュを得ます。
const msgHash = EthUtil.sha3(MSG)
console.log(EthUtil.bufferToHex(msgHash))
// => 0xb826be27896975a66f168f81f553fe0b2f87599d63d01c3b93c1a8a6f2243e5d
// ecrecover を使用して、メッセージの署名を検証します。
const publicKey = EthUtil.ecrecover(msgHash,
SIGNED_MSG.v,
EthUtil.toBuffer(SIGNED_MSG.r),
EthUtil.toBuffer(SIGNED_MSG.s))
// ecrecover により得られた公開鍵から署名者のアドレスを計算します。
const address = EthUtil.pubToAddress(publicKey)
console.log(EthUtil.bufferToHex(address))
// => 0x89c24a88bad4abe0a4f5b2eb5a86db1fb323832c
// 署名者のアドレスと計算されたアドレスを比較します。
if (EthUtil.bufferToHex(address) == SIGNER_ADDRESS_STRING) {
console.log('署名検証に成功しました!')
}
Note
hideyoshi.icon この例では、 MSG と SIGNED_MSG と分けていますが、SIGNED_MSG が MSG を含んでいるほうが自然な気がするので、SIGNED_MSG に msg という要素を入れたほうがいい気がします。
実際に Ethereum の署名済みトランザクションも、メッセージと r, s, v が RLP エンコーディングされています。
関連
Solidity を使用して署名を検証する方法はこちら